﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace Brainee.NeuralNetwork
{
  public class Network : IEnumerable<Layer>
  {
    #region Private fields

    private List<Layer> _layers;

    #endregion
    #region Public properties

    public ICollection<Layer> Layers { get { return _layers; } }

    public Layer this [int index] { get { return _layers [index]; } }

    #endregion
    #region Construction

    public Network (int inputs) 
    {
      _layers = new List<Layer> () {
        new InputLayer(inputs)
      };
    }

    #endregion

    public void Randomize ()
    {
      foreach (Layer l in _layers)
      {
        l.Randomize ();
      }
    }

    public double [] Compute (double [] stim)
    {
      if (stim.Length != _layers [0].OutputCount)
        throw new ArgumentException ();

      Layer layer = _layers [0];
      while (layer != null)
      {
        stim = layer.Compute (stim);
        layer = layer.Next;
      };

      return stim;
    }

    #region IEnumerable<Layer> Members

    public IEnumerator<Layer> GetEnumerator ()
    {
      return _layers.GetEnumerator();
    }

    #endregion
    #region IEnumerable Members

    IEnumerator IEnumerable.GetEnumerator ()
    {
      return _layers.GetEnumerator ();
    }

    #endregion

    public void Add (Layer item)
    {
      if (_layers.Count == 0)
      {
      }
      else
      {
        item.Previous = _layers.Last ();
      }

      if (_layers.Count != 0 && (_layers [_layers.Count - 1].OutputCount != item.InputCount))
        throw new ArgumentException ("The added layer must be adapted to the last layer of the network.");
      
      _layers.Add (item);
    }

    public int Count
    {
      get { return _layers.Count; }
    }
  }
}
